# LeetCode 235、二叉搜索树的最近公共祖先

# 一、题目描述

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

# 二、题目解析

# 三、参考代码

# 1、Java 代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// 二叉搜索树的最近公共祖先( LeetCode 235 ):https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        // 二叉搜索树的特点是,对于每一个节点 root 来说
        // root.left < root < root.right

        // 如果说 root 是 p、q 的最近公共祖先,也就意味值 p、q 在 root 的两侧
        // 假设 p 在 root 的左侧,q 在 root 的右侧
        // 那么 p.val < root.val < q.val
        // 1、root.val - p.val > 0
        // 2、root.val - q.val < 0
        // 即 ( root.val - p.val ) * ( root.val - q.val ) < 0
        // 所以,如果发现 ( root.val - p.val ) * ( root.val - q.val ) > 0 
        // 说明 p、q 在 root 的同一侧,不是最近公共祖先
        // 需要搜索 root 的左右子树

        // 由于所有节点的值都是唯一的,当出现 ( root.val - p.val ) * ( root.val - q.val ) = 0 时
        // 说明 p、q 中有一个节点是 root 节点,即 p 是 q 的祖先节点,或者 q 是 p 的祖先节点
        while (long) (root.val - p.val) * (root.val - q.val) > 0 ){

            // 当进入到这个循环的时候,说明 p、q 在 root 的同一侧

            // 如果 p.val < root.val,也说明 q.val < root.val,因为只有这样,乘积才能大于 0
            if( p.val < root.val ){

                // 接下来往左子树寻找
                root = root.left;

            // 如果 p.val > root.val,也说明 q.val > root.val,因为只有这样,乘积才能大于 0
            }else{

                // 接下来往右子树寻找
                root = root.right;
            }
        }

        // 跳出循环,说明 (root.val - p.val) * (root.val - q.val) <= 0 
        // 此时,root 就是 p 、q 的最近公共祖先节点
        return root;
    }

}

# 2、C++ 代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// 二叉搜索树的最近公共祖先( LeetCode 235 ):https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {

        // 二叉搜索树的特点是,对于每一个节点 root 来说
        // root->left < root < root->right

        // 如果说 root 是 p、q 的最近公共祖先,也就意味值 p、q 在 root 的两侧
        // 假设 p 在 root 的左侧,q 在 root 的右侧
        // 那么 p->val < root->val < q->val
        // 1、root->val - p->val > 0
        // 2、root->val - q->val < 0
        // 即 ( root->val - p->val ) * ( root->val - q->val ) < 0
        // 所以,如果发现 ( root->val - p->val ) * ( root->val - q->val ) > 0 
        // 说明 p、q 在 root 的同一侧,不是最近公共祖先
        // 需要搜索 root 的左右子树

        // 由于所有节点的值都是唯一的,当出现 ( root->val - p->val ) * ( root->val - q->val ) = 0 时
        // 说明 p、q 中有一个节点是 root 节点,即 p 是 q 的祖先节点,或者 q 是 p 的祖先节点
        while ( (root->val - p->val) * (root->val - q->val) > 0 ){

            // 当进入到这个循环的时候,说明 p、q 在 root 的同一侧

            // 如果 p->val < root->val,也说明 q->val < root->val,因为只有这样,乘积才能大于 0
            if( p->val < root->val ){

                // 接下来往左子树寻找
                root = root->left;

            // 如果 p->val > root->val,也说明 q->val > root->val,因为只有这样,乘积才能大于 0
            }else{

                // 接下来往右子树寻找
                root = root->right;
            }
        }

        // 跳出循环,说明 (root->val - p->val) * (root->val - q->val) <= 0 
        // 此时,root 就是 p 、q 的最近公共祖先节点
        return root;
    }

};

# 3、Python 代码

登录 AlgoMooc 官网获取更多算法图解
# https://www.algomooc.com
# 作者:程序员吴师兄
# 代码有看不懂的地方一定要私聊咨询吴师兄呀
# 二叉搜索树的最近公共祖先( LeetCode 235 ):https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':

        # 二叉搜索树的特点是,对于每一个节点 root 来说
        # root.left < root < root.right

        # 如果说 root 是 p、q 的最近公共祖先,也就意味值 p、q 在 root 的两侧
        # 假设 p 在 root 的左侧,q 在 root 的右侧
        # 那么 p.val < root.val < q.val
        # 1、root.val - p.val > 0
        # 2、root.val - q.val < 0
        # 即 ( root.val - p.val ) * ( root.val - q.val ) < 0
        # 所以,如果发现 ( root.val - p.val ) * ( root.val - q.val ) > 0 
        # 说明 p、q 在 root 的同一侧,不是最近公共祖先
        # 需要搜索 root 的左右子树

        # 由于所有节点的值都是唯一的,当出现 ( root.val - p.val ) * ( root.val - q.val ) = 0 时
        # 说明 p、q 中有一个节点是 root 节点,即 p 是 q 的祖先节点,或者 q 是 p 的祖先节点
        while (root.val - p.val) * (root.val - q.val) > 0 :

            # 当进入到这个循环的时候,说明 p、q 在 root 的同一侧

            # 如果 p.val < root.val,也说明 q.val < root.val,因为只有这样,乘积才能大于 0
            if p.val < root.val :

                # 接下来往左子树寻找
                root = root.left

            # 如果 p.val > root.val,也说明 q.val > root.val,因为只有这样,乘积才能大于 0
            else:

                # 接下来往右子树寻找
                root = root.right


        # 跳出循环,说明 (root.val - p.val) * (root.val - q.val) <= 0 
        # 此时,root 就是 p 、q 的最近公共祖先节点
        return root